from typing import List, Dict, Optional
from sqlalchemy.orm import Session

from app.models.permission import Permission
from app.models.role import Role
from app.exception import ResourceNotFoundError, ValidationError


class PermissionService:
    """权限服务类"""
    
    @staticmethod
    def create_permission(
        db: Session, 
        name: str, 
        code: str, 
        description: str = None,
        parent_id: int = None,
        is_menu: bool = False,
        path: str = None,
        component: str = None,
        icon: str = None,
        sort_order: int = 0
    ) -> Permission:
        """创建权限
        
        Args:
            db: 数据库会话
            name: 权限名称
            code: 权限编码
            description: 权限描述
            parent_id: 父权限ID
            is_menu: 是否为菜单项
            path: 前端路由路径
            component: 前端组件路径
            icon: 图标
            sort_order: 排序序号
            
        Returns:
            Permission: 创建的权限对象
            
        Raises:
            ValidationError: 权限名称或编码已存在
        """
        # 检查权限名称和编码是否已存在
        if db.query(Permission).filter(Permission.name == name).first():
            raise ValidationError(f"权限名称 {name} 已存在")
        
        if db.query(Permission).filter(Permission.code == code).first():
            raise ValidationError(f"权限编码 {code} 已存在")
        
        # 检查父权限是否存在
        if parent_id and not db.query(Permission).filter(Permission.id == parent_id).first():
            raise ValidationError(f"父权限ID {parent_id} 不存在")
            
        # 创建权限
        permission = Permission(
            name=name,
            code=code,
            description=description,
            parent_id=parent_id,
            is_menu=is_menu,
            path=path,
            component=component,
            icon=icon,
            sort_order=sort_order
        )
        
        db.add(permission)
        db.commit()
        db.refresh(permission)
        return permission
    
    @staticmethod
    def get_permission_by_id(db: Session, permission_id: int) -> Permission:
        """通过ID获取权限
        
        Args:
            db: 数据库会话
            permission_id: 权限ID
            
        Returns:
            Permission: 权限对象
            
        Raises:
            ResourceNotFoundError: 权限不存在
        """
        permission = db.query(Permission).filter(Permission.id == permission_id).first()
        if not permission:
            raise ResourceNotFoundError(f"ID为 {permission_id} 的权限不存在")
        return permission
    
    @staticmethod
    def get_permission_by_code(db: Session, code: str) -> Optional[Permission]:
        """通过编码获取权限
        
        Args:
            db: 数据库会话
            code: 权限编码
            
        Returns:
            Optional[Permission]: 权限对象，不存在则返回None
        """
        return db.query(Permission).filter(Permission.code == code).first()
    
    @staticmethod
    def get_permission_list(db: Session) -> List[Permission]:
        """获取权限列表
        
        Args:
            db: 数据库会话
            
        Returns:
            List[Permission]: 权限列表
        """
        return db.query(Permission).all()
    
    @staticmethod
    def get_permission_tree(db: Session) -> List[Dict]:
        """获取权限树结构
        
        Args:
            db: 数据库会话
            
        Returns:
            List[Dict]: 权限树结构列表
        """
        # 获取所有权限
        all_permissions = db.query(Permission).order_by(Permission.sort_order).all()
        
        # 将权限按ID索引，便于查找
        permissions_by_id = {perm.id: perm for perm in all_permissions}
        
        # 构建树结构
        permission_dict = {}
        for perm in all_permissions:
            permission_dict[perm.id] = {
                "id": perm.id,
                "name": perm.name,
                "code": perm.code, 
                "description": perm.description,
                "parent_id": perm.parent_id,
                "is_menu": perm.is_menu,
                "path": perm.path,
                "component": perm.component,
                "icon": perm.icon,
                "sort_order": perm.sort_order,
                "children": []
            }
        
        # 找出所有顶级权限和子权限关系
        top_level_permissions = []
        for perm_id, perm_data in permission_dict.items():
            parent_id = perm_data["parent_id"]
            if parent_id is None:
                # 顶级权限
                top_level_permissions.append(perm_data)
            else:
                # 将子权限添加到父权限的children列表中
                if parent_id in permission_dict:
                    permission_dict[parent_id]["children"].append(perm_data)
        
        # 对各级权限进行排序
        def sort_permissions(permissions):
            # 按sort_order排序
            permissions.sort(key=lambda x: x["sort_order"])
            # 递归排序子权限
            for perm in permissions:
                if perm["children"]:
                    sort_permissions(perm["children"])
            return permissions
        
        # 返回排序后的顶级权限树
        return sort_permissions(top_level_permissions)
    
    @staticmethod
    def update_permission(
        db: Session, 
        permission_id: int, 
        **kwargs
    ) -> Permission:
        """更新权限信息
        
        Args:
            db: 数据库会话
            permission_id: 权限ID
            **kwargs: 要更新的字段
            
        Returns:
            Permission: 更新后的权限对象
            
        Raises:
            ResourceNotFoundError: 权限不存在
            ValidationError: 权限名称或编码已存在
        """
        permission = PermissionService.get_permission_by_id(db, permission_id)
        
        # 检查名称唯一性
        if "name" in kwargs and kwargs["name"] != permission.name:
            if db.query(Permission).filter(Permission.name == kwargs["name"]).first():
                raise ValidationError(f"权限名称 {kwargs['name']} 已存在")
        
        # 检查编码唯一性
        if "code" in kwargs and kwargs["code"] != permission.code:
            if db.query(Permission).filter(Permission.code == kwargs["code"]).first():
                raise ValidationError(f"权限编码 {kwargs['code']} 已存在")
        
        # 检查父权限是否存在
        if "parent_id" in kwargs and kwargs["parent_id"]:
            if not db.query(Permission).filter(Permission.id == kwargs["parent_id"]).first():
                raise ValidationError(f"父权限ID {kwargs['parent_id']} 不存在")
                
            # 防止循环引用
            if kwargs["parent_id"] == permission_id:
                raise ValidationError("不能将自身设为父权限")
        
        # 更新权限信息
        for key, value in kwargs.items():
            if hasattr(permission, key):
                setattr(permission, key, value)
        
        db.commit()
        db.refresh(permission)
        return permission
    
    @staticmethod
    def delete_permission(db: Session, permission_id: int) -> bool:
        """删除权限
        
        Args:
            db: 数据库会话
            permission_id: 权限ID
            
        Returns:
            bool: 是否删除成功
            
        Raises:
            ResourceNotFoundError: 权限不存在
            ValidationError: 权限有子权限，不能删除
        """
        permission = PermissionService.get_permission_by_id(db, permission_id)
        
        # 检查是否有子权限
        if db.query(Permission).filter(Permission.parent_id == permission_id).count() > 0:
            raise ValidationError(f"权限 {permission.name} 有子权限，无法删除")
        
        # 删除权限
        db.delete(permission)
        db.commit()
        return True
    
    @staticmethod
    def assign_permission_to_role(db: Session, role_id: int, permission_id: int) -> bool:
        """为角色分配权限
        
        Args:
            db: 数据库会话
            role_id: 角色ID
            permission_id: 权限ID
            
        Returns:
            bool: 是否分配成功
            
        Raises:
            ResourceNotFoundError: 角色或权限不存在
            ValidationError: 角色已拥有该权限
        """
        # 检查角色是否存在
        role = db.query(Role).filter(Role.id == role_id).first()
        if not role:
            raise ResourceNotFoundError(f"ID为 {role_id} 的角色不存在")
            
        # 检查权限是否存在
        permission = PermissionService.get_permission_by_id(db, permission_id)
        
        # 检查角色是否已拥有该权限
        if permission in role.permissions:
            raise ValidationError(f"角色 {role.name} 已拥有权限 {permission.name}")
            
        # 为角色分配权限
        role.permissions.append(permission)
        db.commit()
        return True
    
    @staticmethod
    def remove_permission_from_role(db: Session, role_id: int, permission_id: int) -> bool:
        """从角色移除权限
        
        Args:
            db: 数据库会话
            role_id: 角色ID
            permission_id: 权限ID
            
        Returns:
            bool: 是否移除成功
            
        Raises:
            ResourceNotFoundError: 角色或权限不存在
            ValidationError: 角色未拥有该权限
        """
        # 检查角色是否存在
        role = db.query(Role).filter(Role.id == role_id).first()
        if not role:
            raise ResourceNotFoundError(f"ID为 {role_id} 的角色不存在")
            
        # 检查权限是否存在
        permission = PermissionService.get_permission_by_id(db, permission_id)
        
        # 检查角色是否拥有该权限
        if permission not in role.permissions:
            raise ValidationError(f"角色 {role.name} 未拥有权限 {permission.name}")
            
        # 从角色移除权限
        role.permissions.remove(permission)
        db.commit()
        return True
    
    @staticmethod
    def get_role_permissions(db: Session, role_id: int) -> List[Permission]:
        """获取角色拥有的权限
        
        Args:
            db: 数据库会话
            role_id: 角色ID
            
        Returns:
            List[Permission]: 权限列表
            
        Raises:
            ResourceNotFoundError: 角色不存在
        """
        # 检查角色是否存在
        role = db.query(Role).filter(Role.id == role_id).first()
        if not role:
            raise ResourceNotFoundError(f"ID为 {role_id} 的角色不存在")
            
        return role.permissions
